Разработка приложения Sushi App. Часть 1
➡️Ссылка на репозиторий с кодом этого урока (ветка main)
Данные и модели
Теперь интересный и новый материал. Обычно данные для подобных приложений, загружаются из базы данных. В данном случае для упрощения, мы подготовим локальные данные и будем хранить их внутри приложения.
В папку models добавим файл roll.dart
В папку data добавим файл rolls_data.dart
Файл roll.dart
/// Модель ролла, используемая для хранения его данных.
///
/// Каждый объект (экземпляр) класса Roll содержит информацию о ролле:
/// Имя, описание, URL-адрес изображения и цену.
///
/// Используется в сочетании с виджетом [RollCard] для отображения
/// информации о ролле на экране.
class Roll {
final int id;
final String name;
final String description;
final String fullDescription;
final String imageUrl;
final double price;
Roll({
required this.id,
required this.name,
required this.description,
required this.fullDescription,
required this.imageUrl,
required this.price,
});
}
Файл rolls_data.dart
// Данные о роллах
import '../models/roll.dart';
final List<Roll> data = [
Roll(
id: 1,
name: "Филадельфия",
description: "Лосось, сыр, авокадо",
imageUrl: "assets/images/roll1.png",
price: 450.0,
fullDescription:
"Филадельфия - это классический ролл, созданный для истинных гурманов. Сочетание свежего лосося, нежного сыра и авокадо создает неповторимый вкус. Этот ролл, с вдохновением названный в честь города Филадельфия, завоевал сердце миллионов благодаря своей изысканности и балансу ингредиентов.",
),
Roll(
id: 2,
name: "Калифорния",
description: "Краб, авокадо, икра",
imageUrl: "assets/images/roll2.png",
price: 500.0,
fullDescription:
"Калифорния - это ролл, который откроет вам новые горизонты вкуса. Сладкий краб в сочетании со свежестью авокадо и пикантной икрой - идеальный выбор для тех, кто ищет экзотические впечатления. Этот ролл был создан в Калифорнии и быстро стал хитом среди любителей суши за его уникальный вкус и презентацию.",
),
Roll(
id: 3,
name: "Дракон",
description: "Угорь, авокадо, кунжут",
imageUrl: "assets/images/roll3.png",
price: 550.0,
fullDescription:
"Дракон - это ролл, который всегда будет в центре внимания. Нежный угорь в сочетании с кремовым авокадо и хрустящим кунжутом создает незабываемый вкус. Этот ролл не только порадует вас своими вкусовыми качествами, но и удивит своей великолепной подачей и загадочной историей создания.",
),
Roll(
id: 4,
name: "Ролл с креветкой",
description: "Креветка, огурец, соус",
imageUrl: "assets/images/roll4.png",
price: 400.0,
fullDescription:
"Ролл с креветкой - это легкое и освежающее блюдо, которое понравится каждому. Сочные креветки, свежий огурец и уникальный соус делают этот ролл идеальным выбором для тех, кто ищет что-то особенное. Это блюдо, созданное на основе традиционных рецептов, станет настоящим украшением вашего стола.",
),
Roll(
id: 5,
name: "Вегетарианский ролл",
description: "Огурец, авокадо, перец",
imageUrl: "assets/images/roll5.png",
price: 350.0,
fullDescription:
"Вегетарианский ролл - это праздник для всех любителей овощей. Сочетание свежих огурцов, мягкого авокадо и сочного перца создают легкий и вкусный ролл, который подойдет как для вегетарианцев, так и для тех, кто хочет сделать паузу от мяса.",
),
Roll(
id: 6,
name: "Запеченный ролл",
description: "Лосось, сыр, спайси соус",
imageUrl: "assets/images/roll6.png",
price: 600.0,
fullDescription:
"Запеченный ролл - это шедевр японской кухни. Сочетание нежного лосося, кремового сыра и острого спайси соуса создают уникальный вкус, который невозможно забыть. Этот ролл, запеченный до совершенства, станет вашим любимым блюдом, которое вы захотите заказывать снова и снова.",
),
Roll(
id: 7,
name: "Подозрительный ролл",
description: "Хммм ...",
imageUrl: "assets/images/roll7.png",
price: 9999.0,
fullDescription:
"Ты не станешь неуязвимым, но… Можешь почувствовать себя: Богом интерьерного дизайна, потому что ковёр начнёт двигаться, как океан. Избранным, которому открылись тайны вселенной (спойлер: утром ты их не вспомнишь). Персонажем триллера, когда поймёшь, что твои руки — это на самом деле ноги.",
),
];
Теперь нужно правильно использовать эти данные!
Исправим код карточки RollCard. Теперь вместо значений, которые были прописаны вручную, мы укажем ссылки на объект Roll
Файл roll_card.dart
import 'package:flutter/material.dart';
import '../models/roll.dart';
class RollCard extends StatelessWidget {
final Roll roll; // Переменная для хранения данных о ролле
const RollCard({super.key, required this.roll});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Card(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
child: Image.asset(
roll.imageUrl, // Путь к изображению через объект roll
width: double.infinity,
fit: BoxFit.cover,
),
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(roll.name), // Название ролла через объект roll
subtitle: Text(
roll.description, // Описание ролла через объект roll
style: const TextStyle(fontSize: 10),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("${roll.price} руб."), // Цена ролла через объект roll
TextButton(
onPressed: () {
// Здесь можно добавить логику покупки
},
child: const Text("Купить"),
),
],
),
],
),
),
),
);
}
}
Далее нужно при вызове виджета RollCard передавать в него данные по индексу из массива с настоящими данными
Файл main_screen.dart
import 'package:flutter/material.dart';
import '../models/roll.dart';
import '../data/rolls_data.dart';
import '../widgets/roll_card.dart';
class MainScreen extends StatefulWidget {
MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
final List<Roll> rolls = data; // Данные для списка роллов
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sushi Shop'),
actions: <Widget>[
IconButton(
icon: Badge.count(count: 99, child: const Icon(Icons.shopping_cart)),
tooltip: 'Корзина',
// Чтобы Badge обновился при возврате назад на этот экран
onPressed: () {
},
),
],
),
body: GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 12),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // Указываем количество колонок
crossAxisSpacing: 8.0, // Отступ между колонками
mainAxisSpacing: 8.0, // Отступ между строками
childAspectRatio: 0.85, // Соотношение сторон карточки
),
itemCount: rolls.length, // Количество элементов в списке
itemBuilder: (context, index) {
return RollCard(
roll: rolls[index],
);
},
),
);
}
}
Есть массив rolls объектов Roll с конкретными данными из файла rolls_data.dart
final List<Roll> rolls = data; // Данные для списка роллов
Виджет GridView создаёт в цикле каждый элемент списка, передавая индекс от 0 до длины массива с роллами rolls.length
В виджет RollCard передается объект из массива по определенному индексу.
Cначала создается карточка с данными из массива по индексу 0, потом по индексу 1 и т.д.
itemCount: rolls.length, // Количество элементов в списке
itemBuilder: (context, index) {
return RollCard(
roll: rolls[index],
);
},
В результате экране будет список всех товаров из файла с данными rolls_data.dart
